/*
 * PsMediaWriter.cpp
 *
 *  Created on: 2018年4月27日
 *      Author: zhengboyuan
 */

#include "PsMediaWriter.h"
#include "MFormatUtil.h"
#include "Ffmpeg.h"
#include "AacHelper.h"
#include "TFileUtil.h"

namespace av
{

PsMediaWriter::PsMediaWriter() :
	m_file(),
	m_totalBytes(),
	m_format(),
	m_startPts(-1),
	m_curPts(),
	m_listener()
{
	m_adtsBuffer.ensure(1024);
}

PsMediaWriter::~PsMediaWriter()
{
	close();
}

bool PsMediaWriter::open(const char* filename, const MFormat& fmt)
{
	if (!filename || (strlen(filename) == 0))
	{
		return false;
	}

	m_file = fopen(filename, "wb");

	MFormatUtil::copyTo(&fmt, m_fmt);
	if (m_fmt.m_clockRate <= 0)
	{
		m_fmt.m_clockRate = 90000;
	}

	if (m_fmt.m_audioRate <= 0)
	{
		m_fmt.m_audioRate = m_fmt.m_sampleRate;
	}

	m_muxer.setCodec(fmt.codec, fmt.audioCodec);

	return (m_file != NULL);
}

void PsMediaWriter::close()
{
	if (m_file)
	{
		fclose(m_file);
		m_file = NULL;
	}

	m_totalBytes = 0;
	m_startPts = -1;
	m_curPts = 0;
}

bool PsMediaWriter::isOpen()
{
	return (m_file != NULL);
}

bool PsMediaWriter::getFormat(MFormat& fmt)
{
	fmt = m_format;
	return true;
}

bool PsMediaWriter::writeVideo(uint8_t* data, int size, int64_t pts, int flags)
{
	if (!data || (size <= 0))
	{
		return false;
	}

	if (m_startPts == -1)
	{
		m_startPts = pts;
	}

	m_curPts = pts;

	bool done = false;
	if (m_file == NULL)
	{
		return false;
	}

	bool keyFrame = ((flags & av::MEDIA_FLAG_KEY) != 0);
	if (m_fmt.m_clockRate != 90000)
	{
		pts = av_rescale(pts, 90000, m_fmt.m_clockRate);
	}

	uint8_t* outData = NULL;
	int outSize = 0;
	
	m_muxer.writeVideo(data, size, keyFrame, pts, outData, outSize);
	if (outData && outSize > 0)
	{
		size_t written = fwrite(outData, 1, outSize, m_file);
		done = (written == outSize);

		m_totalBytes += outSize;
	}

	return done;
}

bool PsMediaWriter::writeAudio(uint8_t* data, int size, int64_t pts, int flags)
{
	if (m_fmt.m_audioRate != 90000)
	{
		pts = av_rescale(pts, 90000, m_fmt.m_audioRate);
	}

	if (m_fmt.m_audioCodec == av::MEDIA_CODEC_AAC)
	{
		if (!av::AacHelper::isAdts(data, size))
		{
			m_adtsBuffer.ensure(size + av::AacHelper::ADTS_HEADER_SIZE);

			int profile = (m_fmt.m_audioProfile > 0) ? m_fmt.m_audioProfile : 1;
			av::AacHelper::makeAdtsHeader(profile,
				m_fmt.m_sampleRate, m_fmt.m_channels, size + av::AacHelper::ADTS_HEADER_SIZE,
				m_adtsBuffer.data(), size);
			memcpy(m_adtsBuffer.data() + av::AacHelper::ADTS_HEADER_SIZE, data, size);
			data = m_adtsBuffer.data();
			size += av::AacHelper::ADTS_HEADER_SIZE;
		}
	}

	uint8_t* outData = NULL;
	int outSize = 0;
	m_muxer.writeAudio(data, size, pts, outData, outSize);
	if (outData && outSize > 0)
	{
		fwrite(outData, 1, outSize, m_file);
		m_totalBytes += outSize;
	}
	return true;
}


int PsMediaWriter::getDuration()
{
	return (int)((m_curPts - m_startPts) / 1000);
}

int64_t PsMediaWriter::getByteLength()
{
	return m_totalBytes;
}

bool PsMediaWriter::setFile(const char* filepath)
{
	if (m_file)
	{
		fclose(m_file);
		m_file = NULL;
	}

	m_file = fopen(filepath, "wb");

	return (m_file != NULL);
}

bool PsMediaWriter::setOutputAudioCodec(int codecId)
{
	return false;
}

void PsMediaWriter::setListener(MediaWriterListener* listener)
{
	m_listener = listener;
}

void PsMediaWriter::fireStatus(int status)
{
	if (m_listener)
	{
		m_listener->onWriteStatus(this, status);
	}
}

bool PsMediaWriter::setMeta(const char* key, const char* value, int size)
{
	return true;
}

} /* namespace av */
